package com.dms.modules.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dms.common.security.SecurityUtils;
import com.dms.modules.product.entity.*;
import com.dms.modules.product.mapper.*;
import com.dms.modules.product.service.*;
import com.dms.modules.product.vo.ProductDetailVO;
import com.dms.modules.product.vo.ExperimentGroupInfo;
import com.dms.modules.user.entity.UserBrowseHistory;
import com.dms.modules.user.service.UserBehaviorService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.apache.commons.lang3.StringUtils;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 商品推荐服务实现类
 * 实现了基于A/B测试的混合推荐系统，包含：
 * 1. 个性化推荐（基于用户行为和商品相似度）
 * 2. 基于浏览历史的推荐
 * 3. 基于收藏的推荐
 * 4. 基于搜索历史的推荐
 * 5. 热门商品推荐
 * 6. 新品推荐
 */
@Slf4j
@Service
public class ProductRecommendationServiceImpl implements ProductRecommendationService {

    // =============== 依赖注入 ===============
    @Autowired
    private UserBehaviorService userBehaviorService;
    
    @Autowired
    private ProductMapper productMapper;
    
    @Autowired
    private ProductSimilarityMapper productSimilarityMapper;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private ProductRecommendationExperimentMapper experimentMapper;

    @Autowired
    private ProductCategoryService categoryService;

    @Autowired
    private ProductSkuService skuService;
    
    // =============== 常量定义 ===============
    // Redis缓存键前缀
    private static final String RECOMMENDATION_PREFIX = "product:recommendation:";
    private static final String SIMILAR_PREFIX = "product:similar:";
    private static final String HOT_PREFIX = "product:hot:";
    private static final String NEW_PREFIX = "product:new:";
    private static final String METRICS_PREFIX = "product:metrics:";
    
    // 缓存过期时间（小时）
    private static final long CACHE_EXPIRE_HOURS = 24;

    // =============== 核心推荐接口实现 ===============
    
    /**
     * 获取个性化推荐商品
     * 根据用户ID确定实验组，执行不同的推荐策略
     */
    @Override
    public List<ProductDetailVO> getPersonalizedRecommendations(Long userId, Integer limit) {
        // 获取实验组
        String group = getExperimentGroup(userId);
        
        // 根据实验组选择推荐策略
        List<ProductDetailVO> recommendations;
        if ("A".equals(group)) {
            recommendations = getPersonalizedRecommendationsA(userId, limit);
        } else {
            recommendations = getPersonalizedRecommendationsB(userId, limit);
        }
        
        // 记录推荐结果用于效果分析
        recordRecommendation(userId, "personalized", group, 
            recommendations.stream().map(ProductDetailVO::getId).collect(Collectors.toList()));
            
        return recommendations;
    }

    /**
     * A组推荐策略：基于用户行为的个性化推荐
     * 权重配置：
     * - 浏览行为权重：0.3
     * - 收藏行为权重：0.4
     * - 时间衰减权重：0.3
     */
    private List<ProductDetailVO> getPersonalizedRecommendationsA(Long userId, Integer limit) {
        // 1. 获取用户行为数据
        List<Map<String, Object>> favoriteMaps = userBehaviorService.getUserFavorites(userId);
        List<Map<String, Object>> browseHistoryMaps = userBehaviorService.getUserBrowseHistory(userId);
        
        // 2. 转换数据结构
        List<ProductFavorite> favorites = convertToFavorites(favoriteMaps);
        List<UserBrowseHistory> browseHistory = convertToBrowseHistory(browseHistoryMaps);
        
        // 3. 获取相关商品ID
        Set<Long> productIds = new HashSet<>();
        favorites.forEach(favorite -> productIds.add(favorite.getProductId()));
        browseHistory.forEach(history -> productIds.add(history.getProductId()));
        
        // 个性化推荐的冷启动处理：如果没有行为数据，返回热门商品
        if (productIds.isEmpty()) {
            return getHotProducts(limit);
        }
        
        // 4. 获取完整的商品信息
        List<Product> products = productMapper.selectProductsWithDetails(new ArrayList<>(productIds));
        List<ProductDetailVO> recommendations = convertToProductDetailVO(products);
        
        // 5. 个性化排序
        recommendations = rankRecommendations(recommendations, userId);
        
        // 6. 限制返回数量
        if (recommendations.size() > limit) {
            recommendations = recommendations.subList(0, limit);
        }
        
        return recommendations;
    }

    /**
     * B组推荐策略：基于最近浏览商品的相似商品推荐
     * 相似度权重配置：
     * - 类目相似度权重：0.4
     * - 价格相似度权重：0.3
     * - 标签相似度权重：0.3
     */
    private List<ProductDetailVO> getPersonalizedRecommendationsB(Long userId, Integer limit) {
        // 1. 获取用户最近浏览历史
        List<Map<String, Object>> browseHistoryMaps = userBehaviorService.getUserBrowseHistory(userId);
        List<UserBrowseHistory> browseHistory = convertToBrowseHistory(browseHistoryMaps);
       
        //个性化推荐的冷启动处理：
        if (browseHistory.isEmpty()) {
            return getHotProducts(limit);
        }
        
        // 2. 获取最近浏览的商品ID（最近5个）
        Set<Long> recentProductIds = browseHistory.stream()
            .limit(5)
            .map(UserBrowseHistory::getProductId)
            .collect(Collectors.toSet());
            
        // 3. 获取相似商品
        List<ProductSimilarity> similarities = productSimilarityMapper.selectList(
            new LambdaQueryWrapper<ProductSimilarity>()
                .in(ProductSimilarity::getProductId1, recentProductIds)
                .orderByDesc(ProductSimilarity::getSimilarity)
                .last("LIMIT " + (limit * 2))
        );
        
        // 4. 过滤并获取推荐商品ID
        List<Long> recommendedProductIds = similarities.stream()
            .map(ProductSimilarity::getProductId2)
            .filter(id -> !recentProductIds.contains(id))
            .distinct()
            .limit(limit)
            .collect(Collectors.toList());
            
        if (recommendedProductIds.isEmpty()) {
            return getHotProducts(limit);
        }
        
        // 5. 获取完整的商品信息
        List<Product> products = productMapper.selectProductsWithDetails(recommendedProductIds);
        
        return convertToProductDetailVO(products);
    }

    /**
     * 获取相似商品推荐
     */
    @Override
    public List<ProductDetailVO> getSimilarProducts(Long productId, Integer limit) {
        List<Product> similarProducts = productMapper.getSimilarProducts(productId, limit);
        return convertToProductDetailVO(similarProducts);
    }
    
    /**
     * 获取热门商品推荐
     * 基于商品浏览量排序，并使用Redis缓存优化性能
     */
    @Override
    public List<ProductDetailVO> getHotProducts(Integer limit) {
        String cacheKey = HOT_PREFIX + limit;
        
        // 1. 尝试从缓存获取
        List<ProductDetailVO> cachedHot = (List<ProductDetailVO>) redisTemplate.opsForValue().get(cacheKey);
        if (cachedHot != null) {
            return cachedHot;
        }
        
        // 2. 获取热门商品ID
        List<Long> hotProductIds = productMapper.selectList(
            new LambdaQueryWrapper<Product>()
                .eq(Product::getStatus, 1)
                .orderByDesc(Product::getViewCount)
                .last("LIMIT " + limit)
        ).stream().map(Product::getId).collect(Collectors.toList());
        
        // 3. 获取完整的商品信息
        List<Product> hotProducts = productMapper.selectProductsWithDetails(hotProductIds);
        List<ProductDetailVO> hotProductVOs = convertToProductDetailVO(hotProducts);
        
        // 4. 缓存热门商品
        redisTemplate.opsForValue().set(cacheKey, hotProductVOs, CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
        
        return hotProductVOs;
    }
    
    /**
     * 获取新品推荐
     * 基于商品创建时间排序，并使用Redis缓存优化性能
     */
    @Override
    public List<ProductDetailVO> getNewProducts(Integer limit) {
        String cacheKey = NEW_PREFIX + limit;
        
        // 1. 尝试从缓存获取
        List<ProductDetailVO> cachedNew = (List<ProductDetailVO>) redisTemplate.opsForValue().get(cacheKey);
        if (cachedNew != null) {
            return cachedNew;
        }
        
        // 2. 获取新品
        List<Product> newProducts = productMapper.selectList(
            new LambdaQueryWrapper<Product>()
                .eq(Product::getStatus, 1)
                .eq(Product::getIsNew, 1)
                .orderByDesc(Product::getCreateTime)
                .last("LIMIT " + limit)
        );
        
        List<ProductDetailVO> newProductVOs = convertToProductDetailVO(newProducts);
        
        // 3. 缓存新品
        redisTemplate.opsForValue().set(cacheKey, newProductVOs, CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
        
        return newProductVOs;
    }

    // =============== ！！！！推荐算法核心方法 ===============
    
    /**
     * 个性化排序
     * 综合考虑商品的多个特征进行排序：
     * 1. 浏览量
     * 2. 用户是否浏览过
     * 3. 用户是否收藏
     * 4. 时间衰减因子
     */
    private List<ProductDetailVO> rankRecommendations(List<ProductDetailVO> recommendations, Long userId) {
        // 获取用户行为数据
        List<Map<String, Object>> browseHistoryMaps = userBehaviorService.getUserBrowseHistory(userId);
        List<Map<String, Object>> favoriteMaps = userBehaviorService.getUserFavorites(userId);
        List<UserBrowseHistory> browseHistory = convertToBrowseHistory(browseHistoryMaps);
        List<ProductFavorite> favorites = convertToFavorites(favoriteMaps);
        
        // 计算每个商品的得分
        Map<Long, Double> productScores = new HashMap<>();
        for (ProductDetailVO product : recommendations) {
            double score = 0.0;
            // 浏览量权重
            score += product.getViewCount() * 0.2;
            // 是否浏览过
            if (browseHistory.stream().anyMatch(h -> h.getProductId().equals(product.getId()))) {
                score += 0.3;
            }
            // 是否收藏
            if (favorites.stream().anyMatch(f -> f.getProductId().equals(product.getId()))) {
                score += 0.3;
            }
            // 时间衰减因子
            long hours = ChronoUnit.HOURS.between(product.getCreateTime(), LocalDateTime.now());
            score *= Math.exp(-hours / 24.0);
            productScores.put(product.getId(), score);
        }
        
        // 根据得分排序
        recommendations.sort((a, b) -> productScores.get(b.getId()).compareTo(productScores.get(a.getId())));
        return recommendations;
    }

    /**
     * 计算商品相似度
     * 当前实现考虑：
     * 1. 类目相似度（权重0.4）
     * 2. 价格相似度（权重0.3）
     * 3. 预留标签相似度（权重0.3）
     */
    private double calculateProductSimilarity(Product p1, Product p2) {
        double similarity = 0.0;
        
        // 类目相似度
        if (p1.getCategoryId() != null && p1.getCategoryId().equals(p2.getCategoryId())) {
            similarity += 0.4;
        }
        
        // 价格相似度
        if (p1.getPrice() != null && p2.getPrice() != null) {
            double priceDiff = Math.abs(p1.getPrice().doubleValue() - p2.getPrice().doubleValue());
            similarity += (1 - priceDiff / 1000) * 0.3;
        }
        
        // TODO: 标签相似度计算（预留）
        
        return similarity;
    }

    // =============== 数据转换工具方法 ===============
    
    /**
     * 将商品实体转换为前端展示VO对象
     * 包含：
     * 1. 商品基本信息
     * 2. 分类信息
     * 3. SKU信息
     * 4. 收藏状态
     */
    private List<ProductDetailVO> convertToProductDetailVO(List<Product> products) {
        if (products == null || products.isEmpty()) {
            return Collections.emptyList();
        }

        // 1. 获取所有商品的分类ID
        Set<Long> categoryIds = products.stream()
            .map(Product::getCategoryId)
            .filter(Objects::nonNull)
            .collect(Collectors.toSet());

        // 2. 批量查询分类信息
        Map<Long, ProductCategory> categoryMap = categoryService.listByIds(categoryIds)
            .stream()
            .collect(Collectors.toMap(ProductCategory::getId, category -> category));

        // 3. 批量查询SKU信息
        List<Long> productIds = products.stream()
            .map(Product::getId)
            .collect(Collectors.toList());
        Map<Long, List<ProductSku>> skuMap = skuService.listByProductIds(productIds)
            .stream()
            .collect(Collectors.groupingBy(ProductSku::getProductId));

        // 4. 获取当前用户ID（如果已登录）
        Long currentUserId = null;
        try {
            currentUserId = SecurityUtils.getCurrentUserId();
        } catch (Exception e) {
            log.debug("Failed to get current user ID", e);
        }

        // 5. 如果用户已登录，批量获取收藏状态
        final Long userId = currentUserId;
        Map<Long, Boolean> favoriteMap = new HashMap<>();
        if (userId != null) {
            List<Long> favoriteProductIds = userBehaviorService.getFavoriteProductIds(userId);
            for (Long productId : productIds) {
                favoriteMap.put(productId, favoriteProductIds.contains(productId));
            }
        }

        // 6. 转换数据
        return products.stream()
            .map(product -> {
                ProductDetailVO vo = new ProductDetailVO();
                // 设置基本信息
                vo.setId(product.getId());
                vo.setMerchantId(product.getMerchantId());
                vo.setCategoryId(product.getCategoryId());
                vo.setName(product.getName());
                vo.setSubtitle(product.getSubtitle());
                vo.setMainImage(product.getMainImage());
                // 处理商品子图
                if (StringUtils.isNotBlank(product.getSubImages())) {
                    vo.setSubImages(Arrays.asList(product.getSubImages().split(",")));
                }
                vo.setDetail(product.getDetail());
                vo.setPrice(product.getPrice());
                vo.setStock(product.getStock());
                vo.setStatus(product.getStatus());
                vo.setAuditStatus(product.getAuditStatus());
                vo.setSales(product.getSales());
                vo.setOriginalPrice(product.getOriginalPrice());
                vo.setIsRecommend(product.getIsRecommend());
                vo.setIsNew(product.getIsNew());
                vo.setIsHot(product.getIsHot());
                vo.setViewCount(product.getViewCount());
                vo.setSpecs(product.getSpecs());
                vo.setParams(product.getParams());
                vo.setFavoriteCount(product.getFavoriteCount());
                vo.setCreateTime(product.getCreateTime());
                vo.setUpdateTime(product.getUpdateTime());
                
                // 设置分类信息
                ProductCategory category = categoryMap.get(product.getCategoryId());
                if (category != null) {
                    vo.setCategory(category);
                }
                
                // 设置SKU列表
                List<ProductSku> skuList = skuMap.get(product.getId());
                if (skuList != null) {
                    vo.setSkuList(skuList);
                }
                
                // 设置收藏状态
                if (userId != null) {
                    vo.setIsFavorite(favoriteMap.get(product.getId()));
                }
                
                return vo;
            })
            .collect(Collectors.toList());
    }

    /**
     * 将Map数据转换为浏览历史对象
     */
    private List<UserBrowseHistory> convertToBrowseHistory(List<Map<String, Object>> browseHistoryMaps) {
        return browseHistoryMaps.stream()
                .map(map -> {
                    UserBrowseHistory history = new UserBrowseHistory();
                    history.setId((Long) map.get("id"));
                    history.setUserId((Long) map.get("userId"));
                    history.setProductId((Long) map.get("productId"));
                    history.setCategoryId((Long) map.get("categoryId"));
                    history.setViewCount((Integer) map.get("viewCount"));
                    history.setStayDuration((Integer) map.get("stayDuration"));
                    history.setLastViewTime((LocalDateTime) map.get("lastViewTime"));
                    history.setCreateTime((LocalDateTime) map.get("createTime"));
                    history.setUpdateTime((LocalDateTime) map.get("updateTime"));
                    history.setDeleted((Integer) map.get("deleted"));
                    return history;
                })
                .collect(Collectors.toList());
    }

    /**
     * 将Map数据转换为收藏对象
     */
    private List<ProductFavorite> convertToFavorites(List<Map<String, Object>> favoriteMaps) {
        return favoriteMaps.stream()
                .map(map -> {
                    ProductFavorite favorite = new ProductFavorite();
                    favorite.setId((Long) map.get("id"));
                    favorite.setUserId((Long) map.get("userId"));
                    favorite.setProductId((Long) map.get("productId"));
                    favorite.setCreateTime((LocalDateTime) map.get("createTime"));
                    return favorite;
                })
                .collect(Collectors.toList());
    }

    // =============== 实验组管理 ===============
    
    /**
     * 获取用户所属实验组
     * 使用Redis缓存实验组信息，有效期30天
     */
    private String getExperimentGroup(Long userId) {
        String key = "product:experiment:" + userId;
        String group = (String) redisTemplate.opsForValue().get(key);
        
        if (group == null) {
            // 获取活跃的实验配置
            List<ProductRecommendationExperiment> experiments = experimentMapper.getActiveExperiments();
            if (experiments.isEmpty()) {
                group = "A"; // 默认使用A组
            } else {
                // 随机选择一个实验组
                int index = (int) (userId % experiments.size());
                group = experiments.get(index).getExperimentGroup();
            }
            
            redisTemplate.opsForValue().set(key, group, 30, TimeUnit.DAYS);
        }
        
        return group;
    }

    /**
     * 查询用户实验组信息
     * @param userIds 用户ID列表
     * @return Map<用户ID, 实验组信息>
     */
    @Override
    public Map<Long, ExperimentGroupInfo> queryUserExperimentGroups(List<Long> userIds) {
        Map<Long, ExperimentGroupInfo> result = new HashMap<>();
        
        // 批量获取Redis中的实验组信息
        List<String> keys = userIds.stream()
            .map(userId -> "product:experiment:" + userId)
            .collect(Collectors.toList());
            
        List<Object> groupValues = redisTemplate.opsForValue().multiGet(keys);
        
        // 获取当前活跃的实验配置
        List<ProductRecommendationExperiment> activeExperiments = experimentMapper.getActiveExperiments();
        Map<String, ProductRecommendationExperiment> experimentMap = activeExperiments.stream()
            .collect(Collectors.toMap(ProductRecommendationExperiment::getExperimentGroup, e -> e));
            
        // 组装结果
        for (int i = 0; i < userIds.size(); i++) {
            Long userId = userIds.get(i);
            String group = (String) groupValues.get(i);
            
            ExperimentGroupInfo info = new ExperimentGroupInfo();
            info.setUserId(userId);
            info.setGroup(group);
            
            // 如果Redis中没有，重新计算分组
            if (group == null) {
                group = getExperimentGroup(userId);
                info.setGroup(group);
                info.setNewlyAssigned(true);
            }
            
            // 获取实验配置信息
            ProductRecommendationExperiment experiment = experimentMap.get(group);
            if (experiment != null) {
                info.setExperimentName(experiment.getExperimentName());
                info.setAlgorithmType(experiment.getAlgorithmType());
                info.setParameters(experiment.getParameters());
            }
            
            result.put(userId, info);
        }
        
        return result;
    }

    /**
     * 清除用户实验组缓存
     * @param userId 用户ID
     */
    @Override
    public void clearUserExperimentGroup(Long userId) {
        String key = "product:experiment:" + userId;
        redisTemplate.delete(key);
    }

    /**
     * 重新分配用户实验组
     * @param userId 用户ID
     * @return 新的实验组信息
     */
    @Override
    public ExperimentGroupInfo reassignUserExperimentGroup(Long userId) {
        // 清除原有缓存
        clearUserExperimentGroup(userId);
        
        // 重新分配实验组
        String newGroup = getExperimentGroup(userId);
        
        // 获取实验配置信息
        ProductRecommendationExperiment experiment = experimentMapper.getActiveExperiments().stream()
            .filter(e -> e.getExperimentGroup().equals(newGroup))
            .findFirst()
            .orElse(null);
            
        // 组装返回信息
        ExperimentGroupInfo info = new ExperimentGroupInfo();
        info.setUserId(userId);
        info.setGroup(newGroup);
        info.setNewlyAssigned(true);
        
        if (experiment != null) {
            info.setExperimentName(experiment.getExperimentName());
            info.setAlgorithmType(experiment.getAlgorithmType());
            info.setParameters(experiment.getParameters());
        }
        
        return info;
    }

    // =============== 定时任务 ===============
    
    /**
     * 定时更新商品相似度
     * 每天凌晨2点执行
     */
    @Scheduled(cron = "0 0 2 * * ?")
    public void updateProductSimilarities() {
        log.info("开始更新商品相似度...");
        List<Product> allProducts = productMapper.selectList(null);
        
        for (int i = 0; i < allProducts.size(); i++) {
            for (int j = i + 1; j < allProducts.size(); j++) {
                Product p1 = allProducts.get(i);
                Product p2 = allProducts.get(j);
                
                // 计算相似度
                double similarity = calculateProductSimilarity(p1, p2);
                
                // 创建相似度记录（双向）
                ProductSimilarity similarity1 = new ProductSimilarity();
                similarity1.setProductId1(p1.getId());
                similarity1.setProductId2(p2.getId());
                similarity1.setSimilarity(new java.math.BigDecimal(similarity));
                similarity1.setSimilarityType("content");
                
                ProductSimilarity similarity2 = new ProductSimilarity();
                similarity2.setProductId1(p2.getId());
                similarity2.setProductId2(p1.getId());
                similarity2.setSimilarity(new java.math.BigDecimal(similarity));
                similarity2.setSimilarityType("content");
                
                // 保存到数据库
                productSimilarityMapper.insert(similarity1);
                productSimilarityMapper.insert(similarity2);
            }
        }
        
        log.info("商品相似度更新完成");
    }

    // =============== 推荐效果统计 ===============
    
    /**
     * 记录推荐结果
     */
    @Override
    public void recordRecommendation(Long userId, String recommendationType, 
            String experimentGroup, List<Long> productIds) {
        String key = METRICS_PREFIX + "recommendation:" + userId + ":" + recommendationType + ":" + experimentGroup;
        redisTemplate.opsForValue().set(key, productIds, CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
    }
    
    /**
     * 记录用户点击
     */
    @Override
    public void recordUserClick(Long userId, Long productId) {
        String key = METRICS_PREFIX + "click:" + userId;
        redisTemplate.opsForList().rightPush(key, productId);
        redisTemplate.expire(key, CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
    }
    
    /**
     * 记录用户浏览
     */
    @Override
    public void recordUserView(Long userId, Long productId) {
        String key = METRICS_PREFIX + "view:" + userId;
        redisTemplate.opsForList().rightPush(key, productId);
        redisTemplate.expire(key, CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
    }
    
    /**
     * 获取推荐效果统计指标
     * 包括：
     * 1. 总推荐数
     * 2. 总点击数
     * 3. 总浏览数
     * 4. 点击率
     * 5. 浏览率
     */
    @Override
    public Map<String, Object> getRecommendationMetrics(String recommendationType, String experimentGroup) {
        Map<String, Object> metrics = new HashMap<>();
        
        // 1. 获取推荐记录
        String recommendationKey = METRICS_PREFIX + "recommendation:*:" + recommendationType + ":" + experimentGroup;
        Set<String> recommendationKeys = redisTemplate.keys(recommendationKey);
        
        // 2. 获取点击记录
        String clickKey = METRICS_PREFIX + "click:*";
        Set<String> clickKeys = redisTemplate.keys(clickKey);
        
        // 3. 获取浏览记录
        String viewKey = METRICS_PREFIX + "view:*";
        Set<String> viewKeys = redisTemplate.keys(viewKey);
        
        // 4. 计算指标
        int totalRecommendations = 0;
        int totalClicks = 0;
        int totalViews = 0;
        
        // 统计推荐数
        for (String key : recommendationKeys) {
            List<Long> productIds = (List<Long>) redisTemplate.opsForValue().get(key);
            if (productIds != null) {
                totalRecommendations += productIds.size();
            }
        }
        
        // 统计点击数
        for (String key : clickKeys) {
            Long size = redisTemplate.opsForList().size(key);
            if (size != null) {
                totalClicks += size;
            }
        }
        
        // 统计浏览数
        for (String key : viewKeys) {
            Long size = redisTemplate.opsForList().size(key);
            if (size != null) {
                totalViews += size;
            }
        }
        
        // 5. 组装指标数据
        metrics.put("totalRecommendations", totalRecommendations);
        metrics.put("totalClicks", totalClicks);
        metrics.put("totalViews", totalViews);
        metrics.put("clickThroughRate", totalRecommendations > 0 ? (double) totalClicks / totalRecommendations : 0);
        metrics.put("viewThroughRate", totalRecommendations > 0 ? (double) totalViews / totalRecommendations : 0);
        
        return metrics;
    }

    // =============== 其他推荐接口实现 ===============
    
    /**
     * 基于用户行为生成推荐
     */
    @Override
    public List<ProductDetailVO> generateRecommendations(Set<Long> userProductIds, Integer limit) {
        if (userProductIds.isEmpty()) {
            // 如果用户没有行为数据，返回热门商品
            return getHotProducts(limit);
        }
        
        // 获取用户浏览过的商品的相似商品
        List<ProductSimilarity> similarities = productSimilarityMapper.selectList(
            new LambdaQueryWrapper<ProductSimilarity>()
                .in(ProductSimilarity::getProductId1, userProductIds)
                .orderByDesc(ProductSimilarity::getSimilarity)
                .last("LIMIT " + (limit * 2))
        );
        
        // 过滤掉用户已经浏览过的商品
        List<Long> recommendedProductIds = similarities.stream()
            .map(ProductSimilarity::getProductId2)
            .filter(id -> !userProductIds.contains(id))
            .distinct()
            .limit(limit)
            .collect(Collectors.toList());
        
        if (recommendedProductIds.isEmpty()) {
            // 如果没有找到相似商品，返回热门商品
            return getHotProducts(limit);
        }
        
        // 获取完整的商品信息
        List<Product> products = productMapper.selectProductsWithDetails(recommendedProductIds);
        
        return convertToProductDetailVO(products);
    }

    /**
     * 获取基于浏览历史的推荐商品
     */
    @Override
    public List<ProductDetailVO> getBrowseHistoryRecommendations(Long userId, Integer limit) {
        List<Map<String, Object>> browseHistoryMaps = userBehaviorService.getUserBrowseHistory(userId);
        List<UserBrowseHistory> browseHistory = convertToBrowseHistory(browseHistoryMaps);
        if (browseHistory.isEmpty()) {
            return getHotProducts(limit);
        }

        Set<Long> recentProductIds = browseHistory.stream()
                .limit(5)
                .map(UserBrowseHistory::getProductId)
                .collect(Collectors.toSet());

        List<ProductSimilarity> similarities = productSimilarityMapper.selectList(
                new LambdaQueryWrapper<ProductSimilarity>()
                        .in(ProductSimilarity::getProductId1, recentProductIds)
                        .orderByDesc(ProductSimilarity::getSimilarity)
                        .last("LIMIT " + (limit * 2))
        );

        List<Long> recommendedProductIds = similarities.stream()
                .map(ProductSimilarity::getProductId2)
                .filter(id -> !recentProductIds.contains(id))
                .distinct()
                .limit(limit)
                .collect(Collectors.toList());

        if (recommendedProductIds.isEmpty()) {
            return getHotProducts(limit);
        }

        return convertToProductDetailVO(productMapper.selectBatchIds(recommendedProductIds));
    }

    /**
     * 获取基于收藏的推荐商品
     */
    @Override
    public List<ProductDetailVO> getFavoriteRecommendations(Long userId, Integer limit) {
        List<Map<String, Object>> favoriteMaps = userBehaviorService.getUserFavorites(userId);
        List<ProductFavorite> favorites = convertToFavorites(favoriteMaps);
        if (favorites.isEmpty()) {
            return getHotProducts(limit);
        }

        Set<Long> favoriteProductIds = favorites.stream()
                .map(ProductFavorite::getProductId)
                .collect(Collectors.toSet());

        List<ProductSimilarity> similarities = productSimilarityMapper.selectList(
                new LambdaQueryWrapper<ProductSimilarity>()
                        .in(ProductSimilarity::getProductId1, favoriteProductIds)
                        .orderByDesc(ProductSimilarity::getSimilarity)
                        .last("LIMIT " + (limit * 2))
        );

        List<Long> recommendedProductIds = similarities.stream()
                .map(ProductSimilarity::getProductId2)
                .filter(id -> !favoriteProductIds.contains(id))
                .distinct()
                .limit(limit)
                .collect(Collectors.toList());

        if (recommendedProductIds.isEmpty()) {
            return getHotProducts(limit);
        }

        return convertToProductDetailVO(productMapper.selectBatchIds(recommendedProductIds));
    }

    /**
     * 获取基于搜索历史的推荐商品
     */
    @Override
    public List<ProductDetailVO> getSearchHistoryRecommendations(Long userId, Integer limit) {
        List<Map<String, Object>> browseHistoryMaps = userBehaviorService.getUserBrowseHistory(userId);
        List<UserBrowseHistory> browseHistory = convertToBrowseHistory(browseHistoryMaps);
        if (browseHistory.isEmpty()) {
            return getHotProducts(limit);
        }

        Set<Long> recentProductIds = browseHistory.stream()
                .limit(5)
                .map(UserBrowseHistory::getProductId)
                .collect(Collectors.toSet());

        List<ProductSimilarity> similarities = productSimilarityMapper.selectList(
                new LambdaQueryWrapper<ProductSimilarity>()
                        .in(ProductSimilarity::getProductId1, recentProductIds)
                        .orderByDesc(ProductSimilarity::getSimilarity)
                        .last("LIMIT " + (limit * 2))
        );

        List<Long> recommendedProductIds = similarities.stream()
                .map(ProductSimilarity::getProductId2)
                .filter(id -> !recentProductIds.contains(id))
                .distinct()
                .limit(limit)
                .collect(Collectors.toList());

        if (recommendedProductIds.isEmpty()) {
            return getHotProducts(limit);
        }

        return convertToProductDetailVO(productMapper.selectBatchIds(recommendedProductIds));
    }

    // =============== 实验组管理补充接口实现 ===============

    /**
     * 获取所有活跃的实验配置
     */
    @Override
    public List<ProductRecommendationExperiment> getActiveExperiments() {
        return experimentMapper.getActiveExperiments();
    }

    /**
     * 获取实验组的用户数量统计
     */
    @Override
    public Map<String, Long> getExperimentGroupUserCounts() {
        Map<String, Long> counts = new HashMap<>();
        
        // 获取所有实验组的key pattern
        Set<String> keys = redisTemplate.keys("product:experiment:*");
        if (keys == null || keys.isEmpty()) {
            return counts;
        }
        
        // 批量获取实验组信息
        List<Object> values = redisTemplate.opsForValue().multiGet(keys);
        
        // 统计各组用户数量
        values.stream()
            .filter(Objects::nonNull)
            .map(String.class::cast)
            .forEach(group -> counts.merge(group, 1L, Long::sum));
            
        return counts;
    }

    /**
     * 获取实验组的效果指标统计
     */
    @Override
    public Map<String, Map<String, Object>> getExperimentGroupMetrics(LocalDateTime startTime, LocalDateTime endTime) {
        Map<String, Map<String, Object>> metrics = new HashMap<>();
        
        // 获取活跃的实验组
        List<ProductRecommendationExperiment> experiments = getActiveExperiments();
        for (ProductRecommendationExperiment experiment : experiments) {
            String group = experiment.getExperimentGroup();
            
            // 获取该组的推荐记录
            List<String> recommendationKeys = new ArrayList<>(
                redisTemplate.keys(METRICS_PREFIX + "recommendation:*:" + group)
            );
            
            // 获取该组的点击记录
            List<String> clickKeys = new ArrayList<>(
                redisTemplate.keys(METRICS_PREFIX + "click:*")
            );
            
            // 获取该组的浏览记录
            List<String> viewKeys = new ArrayList<>(
                redisTemplate.keys(METRICS_PREFIX + "view:*")
            );
            
            // 计算指标
            long totalRecommendations = 0;
            long totalClicks = 0;
            long totalViews = 0;
            
            // 统计推荐数
            List<Object> recommendationValues = redisTemplate.opsForValue().multiGet(recommendationKeys);
            if (recommendationValues != null) {
                for (Object value : recommendationValues) {
                    if (value instanceof List) {
                        totalRecommendations += ((List<?>) value).size();
                    }
                }
            }
            
            // 统计点击数和浏览数
            for (String key : clickKeys) {
                Long size = redisTemplate.opsForList().size(key);
                if (size != null) totalClicks += size;
            }
            
            for (String key : viewKeys) {
                Long size = redisTemplate.opsForList().size(key);
                if (size != null) totalViews += size;
            }
            
            // 组装指标数据
            Map<String, Object> groupMetrics = new HashMap<>();
            groupMetrics.put("totalRecommendations", totalRecommendations);
            groupMetrics.put("totalClicks", totalClicks);
            groupMetrics.put("totalViews", totalViews);
            groupMetrics.put("clickThroughRate", 
                totalRecommendations > 0 ? (double) totalClicks / totalRecommendations : 0);
            groupMetrics.put("viewThroughRate", 
                totalRecommendations > 0 ? (double) totalViews / totalRecommendations : 0);
                
            metrics.put(group, groupMetrics);
        }
        
        return metrics;
    }

    /**
     * 批量重置指定用户组的实验组
     */
    @Override
    public int reassignUsersToGroup(List<Long> userIds, String targetGroup) {
        // 验证目标实验组是否有效
        List<ProductRecommendationExperiment> experiments = getActiveExperiments();
        boolean isValidGroup = experiments.stream()
            .anyMatch(e -> e.getExperimentGroup().equals(targetGroup));
            
        if (!isValidGroup) {
            throw new IllegalArgumentException("Invalid target group: " + targetGroup);
        }
        
        int successCount = 0;
        
        // 批量重置用户实验组
        for (Long userId : userIds) {
            try {
                String key = "product:experiment:" + userId;
                redisTemplate.opsForValue().set(key, targetGroup, 30, TimeUnit.DAYS);
                successCount++;
            } catch (Exception e) {
                log.error("Failed to reassign user {} to group {}", userId, targetGroup, e);
            }
        }
        
        return successCount;
    }

    /**
     * 获取用户在指定时间段内的推荐历史
     */
    @Override
    public List<Map<String, Object>> getUserRecommendationHistory(Long userId, LocalDateTime startTime, LocalDateTime endTime) {
        List<Map<String, Object>> history = new ArrayList<>();
        
        // 获取该用户的所有推荐记录key
        Set<String> keys = redisTemplate.keys(METRICS_PREFIX + "recommendation:" + userId + ":*");
        if (keys == null || keys.isEmpty()) {
            return history;
        }
        
        // 获取推荐记录
        List<Object> values = redisTemplate.opsForValue().multiGet(keys);
        if (values == null) {
            return history;
        }
        
        // 解析记录
        int i = 0;
        for (String key : keys) {
            Object value = values.get(i++);
            if (value instanceof List) {
                // 解析key中的信息
                String[] parts = key.split(":");
                String recommendationType = parts[parts.length - 2];
                String experimentGroup = parts[parts.length - 1];
                
                // 组装历史记录
                Map<String, Object> record = new HashMap<>();
                record.put("userId", userId);
                record.put("recommendationType", recommendationType);
                record.put("experimentGroup", experimentGroup);
                record.put("recommendedProducts", value);
                record.put("timestamp", LocalDateTime.now()); // 实际应用中应该从记录中获取时间
                
                history.add(record);
            }
        }
        
        return history;
    }
} 